﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.IO;
using System.Threading;
using Microsoft.Win32;
using System.Timers;
using DataCollector.Entity;

namespace SerialPorts
{
    public class SerialPortHelper : IDisposable
    {
        protected enum ControlCommands
        {
            ENQ = 0x05, //Enquire
            ACK = 0x06, //Acknowledge
            NAK = 0x15, //Negative Acknowledge
            STX = 0x02, //Start of TEXT
            ETX = 0x03, //End of Text
            CR = 0x0D,
            LF = 0x0A,
            EOT = 0x04, //End of Transmission
        }

        private SerialPort _serialPort;

        private int _defaultTrySendTimes;
        public int DefaultTrySendTimes
        {
            get { return _defaultTrySendTimes; }
            set
            {
                if (value <= 0)
                    _defaultTrySendTimes = 1;
                else
                    _defaultTrySendTimes = value;
            }
        }

        public SerialPort SerialPort
        {
            get { return _serialPort; }
        }

        public SerialPortHelper()
        {
            _serialPort = new SerialPort();
            _serialPort.BaudRate = 115200;
            _serialPort.DataBits = 8;
            _serialPort.StopBits = StopBits.One;
            _serialPort.ReceivedBytesThreshold = 1;
            //_serialPort.Parity = Parity.Even;
            _serialPort.ReadTimeout = 1000;
            _serialPort.WriteTimeout = 1000;
        }

        /// <summary>
        /// 打开端口
        /// </summary>
        /// <param name="portName"></param>
        public void Open(string portName)
        {
            Close();
            try
            {
                _serialPort.PortName = portName;
                _serialPort.Open();
            }
            catch (IOException ex)
            {
                throw new SerialPortException(ex);
            }
            catch (UnauthorizedAccessException ex)
            {
                throw new SerialPortException(ex);
            }
        }

        /// <summary>
        /// 关闭端口
        /// </summary>
        public void Close()
        {
            if (_serialPort.IsOpen)
                _serialPort.Close();
        }

        /// <summary>
        /// 丢弃来自串行驱动程序的接收和发送缓冲区的数据
        /// </summary>
        public void DiscardBuffer()
        {
            SerialPort.DiscardInBuffer();
            SerialPort.DiscardOutBuffer();
        }

        public Action<MonitorResult> MonitorAction { get; set; }
        System.Timers.Timer timer = null;
        private bool started = false;
        public void StartMontior(string portName)
        {
            if (started)
            {
                throw new Exception("已经开始监视！");
            }
            this.Open(portName);
            started = true;
            timer = new System.Timers.Timer(1000);
            timer.Elapsed += new ElapsedEventHandler(timer1_Tick_Monitor);
            timer.Enabled = true;
            DiscardBuffer();
            return;
        }

        public void EndMontior()
        {
            if (!started)
            {
                throw new Exception("还未开始监视！");
            }
            this.Close();
            started = false;
            if (timer != null)
            {
                timer.Enabled = false;
            }
        }

        void timer1_Tick_Monitor(object source, ElapsedEventArgs e)
        {
            try
            {
                string existing = SerialPort.ReadExisting();
                byte[] res = Encoding.ASCII.GetBytes(existing);
                if (res.Length == 23)
                {
                    var xRes = res.Select(i => i.ToString("x2").ToUpper());
                    //string outStr = string.Join(" ", xRes) + Environment.NewLine + OnComm(res);
                    //LogMsg("接收的数据.txt", string.Join(" ", xRes));
                    //LogMsg("分析结果.txt", outStr);
                    if (MonitorAction != null)
                    {
                        MonitorAction(OnComm(res));
                    }
                }
            }
            catch
            {

            }
        }

        private void LogCode(string fileName, int message)
        {
            lock (this)
            {
                string msg = message.ToString("x");
                if (message == 0x7E)
                {
                    msg = msg + "--------------";
                }
                System.Diagnostics.Debug.WriteLine(msg);
                File.AppendAllText(fileName, msg + "\r\n");
            }
        }

        private void LogMsg(string fileName, string allMeg)
        {
            lock (this)
            {
                System.Diagnostics.Debug.WriteLine(allMeg);
                File.AppendAllText(fileName, allMeg + "\r\n");
            }
        }

        private List<byte> btyeList = new List<byte>();

        private MonitorResult OnComm(byte[] recData)
        {
            // 光
            int iPhoto = (recData[14] << 8) + recData[15];
            double dPhoto = (iPhoto / 4096.0) * 1.5 / 100 * 1000000;
            string sPhoto = Math.Round(dPhoto, 2).ToString();
            // 温度
            int iTemperature = (recData[16] << 8) + recData[17];
            double dTemperature = -39.6 + iTemperature * 0.01;
            string sTemperature = Math.Round(dTemperature, 2).ToString();

            // 湿度
            int iHumidity = (recData[18] << 8) + recData[19];
            double dHumidity = -4 + 0.0405 * iHumidity - 2.8 * 0.000001 * iHumidity * iHumidity;
            dHumidity = (dTemperature - 25) * (0.01 + 0.00008 * iHumidity) + dHumidity;
            string sHumidity = Math.Round(dHumidity, 2).ToString();

            //int iHumidity = (cRecData[18] << 8) + cRecData[19];
            //double dHumidity = -4 + 0.0405 * iHumidity - 2.8 * 0.000001 * iHumidity * iHumidity;
            //dHumidity = (dTemperature - 25) * (0.01 + 0.00008 * iHumidity) + dHumidity;
            //CString sHumidity;
            string res = "光照：" + sPhoto + "  温度：" + sTemperature + "  湿度：" + sHumidity;
            MonitorResult mr = new MonitorResult()
            {
                Humidity = dHumidity,
                Illumination = dPhoto,
                Temperature = dTemperature,
                ReceiveedData = recData
            };
            return mr;
        }

        /// <summary>
        /// Dispose
        /// </summary>
        public void Dispose()
        {
            Close();
        }

        public string[] GetCommPortNames()
        {
            return SerialPort.GetPortNames();
        }

        #region old code
        private void timer1_TicktestRead(object source, ElapsedEventArgs e)
        {
            try
            {
                int bt = SerialPort.ReadByte();
                LogCode("testRead.txt", bt);
            }
            catch
            {
            }
        }

        void timer1_Tick(object source, ElapsedEventArgs e)
        {
            try
            {
                lock (btyeList)
                {
                    int bt = SerialPort.ReadByte();
                    LogCode("data.txt", bt);
                    if (bt == 0x7E)
                    {
                        if (btyeList.Count != 22 && btyeList.Count != 0)
                        {
                            btyeList.Clear();
                        }
                        btyeList.Add((byte)bt);
                        if (btyeList.Count == 23)
                        {
                            //string outStr = string.Join(",", btyeList.Select(i => i.ToString("x"))) + Environment.NewLine + OnComm(btyeList.ToArray());
                            // LogMsg("data.txt", outStr);
                            if (MonitorAction != null)
                            {
                                MonitorAction(OnComm(btyeList.ToArray()));
                            }
                            btyeList.Clear();
                        }
                    }
                    else
                        btyeList.Add((byte)bt);

                }
            }
            catch (Exception ex)
            {

            }
        }
        #endregion
    }
}
